#include "XrdDMLog.hh"

XrdDMLog::XrdDMLog ( int debug ) {
    kStdErr = stderr;
//   fDatime = new TDatime();
    fLastRotated = NULL;
    fDebug = debug;
    fLogFile = NULL;
    SetStdErr();
}

XrdDMLog::~XrdDMLog() {
    if ( fLastRotated ) {
//     delete fLastRotated;
    }
//   delete fDatime;
    if ( ( fLogFile ) && ( fLogFile != kStdErr ) ) {
        fclose ( fLogFile );
    }
}

void XrdDMLog::Init ( bool debug ) {
    if ( !gLog ) {
        gLog = new XrdDMLog ( debug );
    } else {
        gLog->Warning ( "Log facility already initialized!" );
    }
}

void XrdDMLog::Delete() {
    if ( gLog ) {
        delete gLog;
    }
}

bool XrdDMLog::SetFile ( const char *fn ) {

    // Close previously opened file, if one
    if ( ( fLogFile ) && ( fLogFile != kStdErr ) ) {
        fclose ( fLogFile );
    }
    fLogFile = fopen ( fn, "a" );
    if ( !fLogFile ) {
        SetStdErr();
        return false;
    }

    fLogFileName = fn;

    time ( &fLastRotated );
    fRotateable = false;
    return true;
}

void XrdDMLog::SetStdErr() {
    if ( ( fLogFile ) && ( fLogFile != kStdErr ) ) {
        fclose ( fLogFile );
    }
    fLogFile = kStdErr;
    fLogFileName = "";
    fRotateable = false;
}

// Return values:
//   0 : not rotated
int XrdDMLog::CheckRotate() {

    return 0;
}

void XrdDMLog::PrintBanner() {
    if ( !fBanner.empty() ) {
        Info ( "%s",fBanner.c_str() );
    }
}

void XrdDMLog::CheckRotateAndFormat ( MsgType_t type, const char *fmt, va_list args ) {

    // Messages are not eventually mangled by several threads trying to write,
    // and in the worst case, even rotate the log file, at the same time
//   TThread::Lock();

    int r = CheckRotate();
    va_list vl1 = {};
    if ( r < 0 ) {
        Format ( kMsgError, "Errors occured rotating logfile!", vl1 );
    } else if ( r > 0 ) {
        if ( !fBanner.empty() ) {
            va_list vl2 = {};
            Format ( kMsgInfo, fBanner.c_str(), vl2 );
        }
        Format ( kMsgOk, "Logfile rotated", vl1 );
    }
    // 0 == no need to rotate
    Format ( type, fmt, args );

//   TThread::UnLock();  // end of the asynchronous code section
}

void XrdDMLog::Format ( MsgType_t type, const char *fmt, va_list args ) {

    char prefix[4];

    switch ( type ) {
    case kMsgOk:
        strcpy ( prefix, "OK!" );
        break;
    case kMsgWarning:
        strcpy ( prefix, "WRN" );
        break;
    case kMsgInfo:
        strcpy ( prefix, "INF" );
        break;
    case kMsgError:
        strcpy ( prefix, "ERR" );
        break;
    case kMsgFatal:
        strcpy ( prefix, "FTL" );
        break;
    case kMsgDebug:
        strcpy ( prefix, "DBG" );
        break;
    }
    time ( &fDatime );
    struct tm * timeinfo = localtime ( &fDatime );
    char buffer [80];
    strftime ( buffer,80,"%c",timeinfo );
    fprintf ( fLogFile, "[%s] *** %s *** ", buffer, prefix );
    vfprintf ( fLogFile, fmt, args );
    fputc ( '\n', fLogFile );
    fflush ( fLogFile );
}

void XrdDMLog::SetDebug ( int debug ) {
    fDebug = debug;
}

void XrdDMLog::Debug ( int debug,const char *fmt, ... ) {
    if ( fDebug >= debug ) {
        va_list args;
        va_start ( args, fmt );
        CheckRotateAndFormat ( kMsgDebug, fmt, args );
        va_end ( args );
    }
}

void XrdDMLog::Info ( const char *fmt, ... ) {
    va_list args;
    va_start ( args, fmt );
    CheckRotateAndFormat ( kMsgInfo, fmt, args );
    va_end ( args );
}

void XrdDMLog::Ok ( const char *fmt, ... ) {
    va_list args;
    va_start ( args, fmt );
    CheckRotateAndFormat ( kMsgOk, fmt, args );
    va_end ( args );
}

void XrdDMLog::Warning ( const char *fmt, ... ) {
    va_list args;
    va_start ( args, fmt );
    CheckRotateAndFormat ( kMsgWarning, fmt, args );
    va_end ( args );
}

void XrdDMLog::Error ( const char *fmt, ... ) {
    va_list args;
    va_start ( args, fmt );
    CheckRotateAndFormat ( kMsgError, fmt, args );
    va_end ( args );
}

void XrdDMLog::Fatal ( const char *fmt, ... ) {
    va_list args;
    va_start ( args, fmt );
    CheckRotateAndFormat ( kMsgFatal, fmt, args );
    va_end ( args );
}
